<?php


namespace Yond\LaravelDomain;

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Str;
use Yond\LaravelDomain\Console\App\ControllerMakeCommand;
use Yond\LaravelDomain\Console\App\FilterMakeCommand;
use Yond\LaravelDomain\Console\App\QueryMakeCommand;
use Yond\LaravelDomain\Console\AppMakeCommand;
use Yond\LaravelDomain\Console\Domain\ActionMakeCommand;
use Yond\LaravelDomain\Console\Domain\DTOMakeCommand;
use Yond\LaravelDomain\Console\Domain\EnumMakeCommand;
use Yond\LaravelDomain\Console\Domain\MigrationMakeCommand;
use Yond\LaravelDomain\Console\Domain\ModelMakeCommand;
use Yond\LaravelDomain\Console\Domain\SeederMakeCommand;
use Yond\LaravelDomain\Console\DomainMakeCommand;
use Yond\LaravelDomain\Console\InstallCommand;

class LaravelDomainServiceProvider extends ServiceProvider
{
    protected $domainApps = [];

    public function register()
    {
        $this->mergeConfigFrom(
            __DIR__.'/../config/yond-domain.php', 'yond-domain'
        );

        $this->registerExtraColumn();
    }

    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerCommands();
        $this->registerJsonPaginate();
        $this->configurePublishing();

        $this->loadJsonTranslationsFrom(__DIR__ . '/../resources/lang');

        $this->bootDomains();
        $this->bootApps();
    }

    /**
     * Register the console commands for the package.
     *
     * @return void
     */
    protected function registerCommands()
    {
        if ($this->app->runningInConsole()) {
            $this->commands([
                InstallCommand::class,
                DomainMakeCommand::class,
                ActionMakeCommand::class,
                MigrationMakeCommand::class,
                ModelMakeCommand::class,
                SeederMakeCommand::class,
                DTOMakeCommand::class,
                EnumMakeCommand::class,

                AppMakeCommand::class,
                ControllerMakeCommand::class,
                FilterMakeCommand::class,
                QueryMakeCommand::class,
            ]);
        }
    }

    protected function registerJsonPaginate()
    {
        Builder::macro('jsonPaginate', function ($defaultSize = 15) {
            $size = (int) request()->input('count');
            if ($size === 0) {
                return $this->get();
            }
            /** @var $this Builder */
            return $this->paginate($size);
        });
    }

    protected function registerExtraColumn()
    {
        Blueprint::macro('extra', function () {
            /**@var Blueprint $this */
            return $this->text('extra')->nullable();
        });
    }

    /**
     * Configure publishing for the package.
     *
     * @return void
     */
    protected function configurePublishing()
    {
        if ($this->app->runningInConsole()) {
            $this->publishes([
                __DIR__ . '/../config/yond-domain.php' => $this->app->configPath('yond-domain.php'),
            ]);
        }
    }

    // 注册模块
    protected function bootDomains()
    {
        $domains = config('yond-domain.domains');

        foreach ($domains as $domain) {
            $this->loadMigrationsFrom(domain_path($domain.'/Database/Migrations'));
        }
    }

    protected function bootApps()
    {
        $domainApps = $this->getDomainApps();

        foreach ($domainApps as $domainApp) {
            if (array_key_exists('config', $domainApp)) {
                $this->mergeConfigFrom($domainApp['config'], $domainApp['name']);
            }
            if (array_key_exists('route', $domainApp)) {
                $this->loadRoutesFrom($domainApp['route']);
            }
        }
    }

    protected function getDomainApps(): array
    {
        if (empty($this->domainApps)) {
            $apps = config('yond-domain.apps', []);
            foreach ($apps as $name => $path) {
                $app = $this->resolveDomainApp($name, $path);
                $this->domainApps[] = $app;
            }
        }
        return $this->domainApps;
    }

    protected function resolveDomainApp($name, $path): array
    {
        if (is_integer($name)) {
            $name = $path;
        }
        $name = Str::snake($name);
        $path = $this->app->basePath('app/' . Str::studly($path));

        $configFile = $path . DIRECTORY_SEPARATOR . 'config.php';
        $routeFile = $path . DIRECTORY_SEPARATOR . 'routes.php';

        $app = [
            'name' => 'app_' . $name,
            'path' => $path,
        ];

        if (file_exists($configFile)) {
            $app['config'] = $configFile;
        }
        if (file_exists($routeFile)) {
            $app['route'] = $routeFile;
        }
        return $app;
    }
}
